`timescale 1ns/100ps

`include "sim_glb.sv"

module tc;

localparam          CLK_PRD                 = 5;

reg                                         rst_n;
reg                                         clk;

reg                                         fifo_wen;
wire                                        fifo_ren;
wire                [5-1:0]                 fifo_cnt;
wire        signed  [4-1:0]                 in_err;

initial begin:CRG
    rst_n=1'b0;
    clk=1'b0;

    fork
        rst_n=#100.5 1'b1;
        forever clk=#CLK_PRD ~clk;
    join
end

RGRS_MNG    rgrs;
initial begin:REGRESS
    rgrs = new("tc_pi_nco", 1);

    rgrs.wait_chks_done(100_000_000);
end

initial begin
    fifo_wen = 1'b0;
    @(posedge rst_n);
    @(posedge clk);
    repeat(1) begin
        fifo_wen = 1'b1;
        @(posedge clk);
    end

    forever begin
        fifo_wen = 1'b0;
        repeat(15) begin
            @(posedge clk);
        end
        fifo_wen = 1'b1;
        @(posedge clk);
    end
end

initial begin
    #500_000;
    rgrs.one_chk_done("pi_nco done.");
end

sfifo_ctrl #(
        .DEPTH                          (16                             ) 	// must DEPTH>=2
) u_fifo ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),

        .fifo_wen                       (fifo_wen                       ),
        .fifo_full                      (                               ),
        .fifo_afull                     (                               ),	// afull

        .fifo_ren                       (fifo_ren                       ),
        .fifo_empty                     (                               ),
        .fifo_aempty                    (                               ),	// aempty

        .fifo_cnt                       (fifo_cnt                       ),

// it's required that cycles from 'mem_wen'==1 to writing wdata into memory_arrary is 1
        .mem_wen                        (                               ),
        .mem_waddr                      (                               ),
// it's required that cycles from 'mem_ren'==1 to reading data out from memory_arrary is 1
        .mem_ren                        (                               ),
        .mem_raddr                      (                               ),

        .cfg_fifo_afull_th              (4'd1                           ),	// afull_th<fifo_cnt<, range is [0:DEPTH-1]
        .cfg_fifo_aempty_th             (4'd1                           ),	// 0<, range is [1:min(DEPTH,2^ADDR_BW-1)]
        .err_fifo_ilf                   (                               ),	// fifo internal logic fault
        .err_fifo_wof                   (                               ),	// fifo write overflow
        .err_fifo_ruf                   (                               )	// fifo read underflow
);

assign in_err = (fifo_cnt==16) ? 7 : (fifo_cnt - 4'd8);

pi_nco #(    // proportional and integral NCO
        .IN_DW                          (4                              ),
        .IN_FW                          (0                              ),
        .PHS_FW                         (8                              ),	// must OUT_FW<=NCO_FW
        .NCO_FW                         (22                             ),	// must NCO_FW<=IN_FW+KI_MAX
        .FREQ_DW                        (22                             ),
        .PINC_DW                        (14                             ),	// must PINC_DW<OUT_DW-OUT_FW+NCO_FW, and PINC_DW<=NCO_FW+IN_DW-IN_FW-KP_MIN
        .IINC_DW                        (12                             ),	// must IINC_DW<OUT_DW-OUT_FW+NCO_FW, IACC is for freqency offset, it's small
        .IACC_FW                        (22                             ),	// must NCO_FW<=IACC_FW<=IN_FW+KI_MAX
        .KP_MAX                         (14                             ),
        .KP_MIN                         (8                              ),
        .KI_MAX                         (28                             ),	// generally KI_MAX>=KP_MAX
        .KI_MIN                         (16                             )
) u_pi_nco ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),
        .cke                            (1'b1                           ),	// cke for NCO and ACC

        .in_vld                         (1'b1                           ),	// refer to cke
        .in_err                         (in_err                         ),	// s(  IN_DW,   IN_FW)
        .out_phs                        (                               ),	// u( OUT_FW,  OUT_FW), only fraction bits
        .out_over_1p                    (fifo_ren                       ),	// NCO over, only integer bits

        .cfg_kp                         (4'd11                          ),	// range [KP_MIN:KP_MAX], gain 
        .cfg_ki                         (5'd22                          ),	// range [KI_MIN:KI_MAX], gain 

        .cfg_freq_word                  (22'd2**18-22'd200              ),	// u(NCO_DW, NCO_FW),  output frequency is F_clk*freq_word/(2^NCO_FW)

        .cfg_ofst_clr                   (1'b0                           ),
        .cfg_ofst_frz                   (1'b0                           ),
        .cfg_ofst_ini                   (12'd0                          ),	// s(IINC_DW, IINC_FW), initial value
        .sts_ofst_rtv                   (                               )	// s(IINC_DW, IINC_FW), real-time value
);

endmodule

